#ifndef __KERNEL_IRQ_H__
#define __KERNEL_IRQ_H__

#include "arch/traps.h"
#include "arch/bitops.h"

#ifdef __cplusplus
extern "C" {
#endif

// types of softirqs
#define TASKLET_SOFTIRQ			(0)

typedef struct irq_controller
{
	const char *name;
	uint (*startup)(uint irq);
	void (*shutdown)(uint irq);
	void (*enable)(uint irq);
	void (*disable)(uint irq);
	void (*ack)(uint irq);
	void (*end)(uint irq);
}
irq_controller_t;

typedef struct irqaction
{
	void (*handler)(int, void*, regs_t*);
	uint flags;
	const char* name;
	void* dev_id;
	struct irqaction* next;
}
irqaction_t;

#define IAF_NORELEASE		(2)

typedef struct irq_desc
{
	uint status;
	irq_controller_t *handler;
	irqaction_t* action;
	spinlock_t lock;
}
irq_desc_t;

extern irq_desc_t irq_desc[NR_IRQS];

// global initialization
void global_init_irq_module(void);

// intr handler
void handle_irq(regs_t regs);

// request an irq
int _request_irq(uint irq, irqaction_t *action);
int request_irq(uint irq, void (*handler)
				(int, void*, regs_t*), uint flags,
				const char *devname, void *dev_id);

// release an irq
void free_irq(uint irq, void *dev_id);

// soft irq
typedef struct softirq_action
{
	void (*action)(struct softirq_action *);
	void *data;
}
softirq_action_t;

// mark (raise) a softirq
#define __cpu_raise_softirq(cpu, nr)	do { softirq_active(cpu) |= (1 << (nr)); } while (0)

static inline void raise_softirq(int nr)
{
	unsigned long flags;

	local_irq_save(flags);
	__cpu_raise_softirq(smp_processor_id(), nr);
	local_irq_restore(flags);
}

typedef struct tasklet_struct
{
	struct tasklet_struct *next;
	uint state;
	uint count;
	void (*func)(uint);
	uint data;
}
tasklet_t;

#define DECLARE_TASKLET(name, func, data)				tasklet_t name = { NULL, 0, 0, func, data }
#define DECLARE_TASKLET_DISABLED(name, func, data)		tasklet_t name = { NULL, 0, 1, func, data }

#define TASKLET_STATE_SCHED				(1)
#define TASKLET_STATE_RUN				(2)

extern tasklet_t *tasklet_vec[NR_CPUS];

#ifdef VIEWS_SMP_ENABLED
#define tasklet_trylock(t)			(!test_and_set_bit(TASKLET_STATE_RUN, &(t)->state))
#define tasklet_unlock_wait(t)		while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { /* NOTHING */ }
#define tasklet_unlock(t)			clear_bit(TASKLET_STATE_RUN, &(t)->state)
#else
#define tasklet_trylock(t)			1
#define tasklet_unlock_wait(t)		do { } while (0)
#define tasklet_unlock(t)			do { } while (0)
#endif

static inline void tasklet_schedule(tasklet_t *t)
{
	if (!t) return;
	if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
	{
		uint flags;
		int cpu = smp_processor_id();

		local_irq_save(flags);
		t->next = tasklet_vec[cpu];
		tasklet_vec[cpu] = t;
		__cpu_raise_softirq(cpu, TASKLET_SOFTIRQ);
		local_irq_restore(flags);
	}
}

static void tasklet_init(tasklet_t *t, void (*func)(uint), uint data)
{
	t->func = func;
	t->data = data;
	t->state = 0;
	t->count = 0;
}

#ifdef __cplusplus
}
#endif
#endif
/* EOF */
